package com.tengju.bff.interfaces.covercharge.util.concurrent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * user increasement threadfactory
 * 
 * @author fanrui
 * @version 1.0.0
 */
public class ExecutorManager {

    private static ExecutorService exec = null;

    private static Object lock = new Object();

    private static Logger LOGGER = LoggerFactory.getLogger(ExecutorManager.class);

    private ExecutorManager() {

    }

    private static ExecutorManager instance = new ExecutorManager();

    public static ExecutorManager getInstance() {
        synchronized (lock) {
            if (exec == null) {
                ThreadFactory threadFactory = new IncreaseNameThreadFactory(ExecutorManager.class);
                exec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 5, threadFactory);
            }

        }
        return instance;
    }

    public void execute(Runnable command) {
        execute(command, true);
    }

    @SuppressWarnings("rawtypes")
    public Future execute(Runnable command, boolean isBackGrand) {

        try {
            if (isBackGrand) {
                exec.execute(command);
                return null;
            } else {
                return exec.submit(command);
            }

        } catch (Exception e) {
            LOGGER.error("async execute error", e);
        }
        return null;
    }

    public void shutdown() {
        if (exec != null) {
            exec.shutdownNow();
        }
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public <T> List<T> executeTask(TaskAction... tasks) {
        final CountDownLatch latch = new CountDownLatch(tasks.length);

        List<Future<T>> futures = new ArrayList<Future<T>>();
        List<T> resultList = new ArrayList<T>();

        for (final TaskAction<T> runnable : tasks) {
            Future<T> future = exec.submit(new Callable<T>() {
                @Override
                public T call() throws Exception {
                    try {
                        return runnable.doInAction();
                    } finally {
                        latch.countDown();
                    }

                }
            });
            futures.add(future);
        }

        try {
            latch.await();
        } catch (InterruptedException e) {
            LOGGER.error("Executing Task is interrupt.", e);
        }

        for (Future<T> future : futures) {
            try {
                T result = future.get();
                if (result != null) {
                    resultList.add(result);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return resultList;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            ExecutorManager.getInstance().execute(new Runnable() {

                @Override
                public void run() {
                    System.out.println("aaa");

                }
            });
        }

    }
}
